// Package converter 转换器
package converter

import (
	"bytes"
	"encoding/base64"
	"encoding/binary"
	"encoding/gob"
	"encoding/json"
	"errors"
	"fmt"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"image/color"
	"io"
	"math"
	"math/big"
	"reflect"
	"strconv"
	"strings"
)

// ToBool 字符串转bool
// 1, t, T, TRUE, true, True 都会被认为是true
// 0, f, F, FALSE, false, False 都会被认为是false
// 其他值都返回错误
func ToBool(str string) (bool, error) {
	return strconv.ParseBool(str)
}

// ToBytes 任意类型转字节数组
func ToBytes(value any) ([]byte, error) {
	tmpValue := reflect.ValueOf(value)
	switch value.(type) {
	case int, int8, int16, int32, int64:
		number := tmpValue.Int()
		buffer := bytes.NewBuffer([]byte{})
		buffer.Reset()
		err := binary.Write(buffer, binary.BigEndian, number)
		return buffer.Bytes(), err
	case uint, uint8, uint16, uint32, uint64:
		number := tmpValue.Uint()
		buffer := bytes.NewBuffer([]byte{})
		buffer.Reset()
		err := binary.Write(buffer, binary.BigEndian, number)
		return buffer.Bytes(), err
	case float32:
		number := float32(tmpValue.Float())
		bits := math.Float32bits(number)
		bytes := make([]byte, 4)
		binary.BigEndian.PutUint32(bytes, bits)
		return bytes, nil
	case float64:
		number := float64(tmpValue.Float())
		bits := math.Float64bits(number)
		bytes := make([]byte, 8)
		binary.BigEndian.PutUint64(bytes, bits)
		return bytes, nil
	case string:
		return []byte(value.(string)), nil
	case bool:
		return strconv.AppendBool([]byte{}, value.(bool)), nil
	case []byte:
		return value.([]byte), nil
	default:
		newValue, err := json.Marshal(value)
		return newValue, err
	}
}

// ToChars 字符串转字符数组
// 输入空字符串返回[""]
// 输入非空字符串返回字符数组
func ToChars(s string) []string {
	c := make([]string, 0, len(s))
	if len(s) == 0 {
		c = append(c, "")
	}
	for _, v := range s {
		c = append(c, string(v))
	}
	return c
}

// ToChannel 数组转通道
// 输入空数组返回nil
// 输入非空数组返回通道
func ToChannel[T any](array []T) <-chan T {
	ch := make(chan T)
	go func() {
		for _, v := range array {
			ch <- v
		}
		close(ch)
	}()
	return ch
}

// ToString 任意类型转字符串
// 输入nil返回空字符串
// 输入非nil返回字符串
func ToString(value any) string {
	if value == nil {
		return ""
	}

	switch val := value.(type) {
	case float32:
		return strconv.FormatFloat(float64(val), 'f', -1, 32)
	case float64:
		return strconv.FormatFloat(val, 'f', -1, 64)
	case int:
		return strconv.FormatInt(int64(val), 10)
	case int8:
		return strconv.FormatInt(int64(val), 10)
	case int16:
		return strconv.FormatInt(int64(val), 10)
	case int32:
		return strconv.FormatInt(int64(val), 10)
	case int64:
		return strconv.FormatInt(val, 10)
	case uint:
		return strconv.FormatUint(uint64(val), 10)
	case uint8:
		return strconv.FormatUint(uint64(val), 10)
	case uint16:
		return strconv.FormatUint(uint64(val), 10)
	case uint32:
		return strconv.FormatUint(uint64(val), 10)
	case uint64:
		return strconv.FormatUint(val, 10)
	case string:
		return val
	case []byte:
		return string(val)
	default:
		b, err := json.Marshal(val)
		if err != nil {
			return ""
		}
		return string(b)
	}
}

// ToJson 任意类型转json字符串
// 输入nil返回空字符串
// 输入非nil返回json字符串
func ToJson(value any) (string, error) {
	jsonStr, err := json.Marshal(value)
	if err != nil {
		return "", err
	}
	return string(jsonStr), nil
}

// ToFloat 任意类型转浮点数
// 输入nil返回0.0
// 输入非nil返回浮点数
func ToFloat(value any) (float64, error) {
	v := reflect.ValueOf(value)

	result := 0.0
	err := fmt.Errorf("ToInt: unvalid interface type %T", value)
	switch value.(type) {
	case int, int8, int16, int32, int64:
		result = float64(v.Int())
		return result, nil
	case uint, uint8, uint16, uint32, uint64:
		result = float64(v.Uint())
		return result, nil
	case float32, float64:
		result = v.Float()
		return result, nil
	case string:
		result, err = strconv.ParseFloat(v.String(), 64)
		if err != nil {
			result = 0.0
		}
		return result, err
	default:
		return result, err
	}
}

// ToInt 任意类型转整数
// 输入nil返回0
// 输入非nil返回整数
func ToInt(value any) (int64, error) {
	v := reflect.ValueOf(value)

	var result int64
	err := fmt.Errorf("ToInt: invalid value type %T", value)
	switch value.(type) {
	case int, int8, int16, int32, int64:
		result = v.Int()
		return result, nil
	case uint, uint8, uint16, uint32, uint64:
		result = int64(v.Uint())
		return result, nil
	case float32, float64:
		result = int64(v.Float())
		return result, nil
	case string:
		result, err = strconv.ParseInt(v.String(), 0, 64)
		if err != nil {
			result = 0
		}
		return result, err
	default:
		return result, err
	}
}

// ToPointer 任意类型转指针
// 输入nil返回nil
func ToPointer[T any](value T) *T {
	return &value
}

func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
	result := make(map[K]V)
	for _, item := range array {
		key, value := iteratee(item)
		result[key] = value
	}
	return result
}

//func StructToMap(value any) (map[string]any, error) {
//
//}

// MapToSlice map转换成切片
// 输入非nil返回切片
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
	result := make([]T, 0, len(aMap))
	for k, v := range aMap {
		result = append(result, iteratee(k, v))
	}
	return result
}

// ColorHexToRGB 颜色16进制转rgb
// 输入非nil返回rgb
func ColorHexToRGB(colorHex string) (red, green, blue int) {
	colorHex = strings.TrimPrefix(colorHex, "#")
	color64, err := strconv.ParseInt(colorHex, 16, 32)
	if err != nil {
		return
	}
	color := int(color64)
	return color >> 16, (color & 0x00FF00) >> 8, color & 0x0000FF
}

// ColorRGBToHex rgb颜色转16进制
// 输入非nil返回16进制
func ColorRGBToHex(red, green, blue int) string {
	r := strconv.FormatInt(int64(red), 16)
	g := strconv.FormatInt(int64(green), 16)
	b := strconv.FormatInt(int64(blue), 16)

	if len(r) == 1 {
		r = "0" + r
	}
	if len(g) == 1 {
		g = "0" + g
	}
	if len(b) == 1 {
		b = "0" + b
	}

	return "#" + r + g + b
}

// EncodeByte 编码字节
// 输入非nil返回编码字节
func EncodeByte(data any) ([]byte, error) {
	buffer := bytes.NewBuffer(nil)
	encoder := gob.NewEncoder(buffer)
	err := encoder.Encode(data)
	if err != nil {
		return nil, err
	}
	return buffer.Bytes(), nil
}

// DecodeByte 解码字节
// 输入非nil返回解码对象
func DecodeByte(data []byte, target any) error {
	buffer := bytes.NewBuffer(data)
	decoder := gob.NewDecoder(buffer)
	return decoder.Decode(target)
}

// ToInterface 将反射值转换为接口类型
// 输入非nil返回接口类型
func ToInterface(v reflect.Value) (value interface{}, ok bool) {
	if v.IsValid() && v.CanInterface() {
		return v.Interface(), true
	}
	switch v.Kind() {
	case reflect.Bool:
		return v.Bool(), true
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int(), true
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint(), true
	case reflect.Float32, reflect.Float64:
		return v.Float(), true
	case reflect.Complex64, reflect.Complex128:
		return v.Complex(), true
	case reflect.String:
		return v.String(), true
	case reflect.Ptr:
		return ToInterface(v.Elem())
	case reflect.Interface:
		return ToInterface(v.Elem())
	default:
		return nil, false
	}
}

func Utf8ToGbk(bs []byte) ([]byte, error) {
	r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewEncoder())
	b, err := io.ReadAll(r)
	return b, err
}

func GbkToUtf8(bs []byte) ([]byte, error) {
	r := transform.NewReader(bytes.NewReader(bs), simplifiedchinese.GBK.NewDecoder())
	b, err := io.ReadAll(r)
	return b, err
}

func ToStandBase64(value any) string {
	if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
		return ""
	}
	switch value.(type) {
	case []byte:
		return base64.StdEncoding.EncodeToString(value.([]byte))
	case string:
		return base64.StdEncoding.EncodeToString([]byte(value.(string)))
	case error:
		return base64.StdEncoding.EncodeToString([]byte(value.(error).Error()))
	default:
		marshal, err := json.Marshal(value)
		if err != nil {
			return ""
		}
		return base64.StdEncoding.EncodeToString(marshal)
	}
}

func ToUrlBase64(value any) string {
	if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
		return ""
	}
	switch value.(type) {
	case []byte:
		return base64.URLEncoding.EncodeToString(value.([]byte))
	case string:
		return base64.URLEncoding.EncodeToString([]byte(value.(string)))
	case error:
		return base64.URLEncoding.EncodeToString([]byte(value.(error).Error()))
	default:
		marshal, err := json.Marshal(value)
		if err != nil {
			return ""
		}
		return base64.URLEncoding.EncodeToString(marshal)
	}
}

func ToRawStdBase64(value any) string {
	if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
		return ""
	}
	switch value.(type) {
	case []byte:
		return base64.RawStdEncoding.EncodeToString(value.([]byte))
	case string:
		return base64.RawStdEncoding.EncodeToString([]byte(value.(string)))
	case error:
		return base64.RawStdEncoding.EncodeToString([]byte(value.(error).Error()))
	default:
		marshal, err := json.Marshal(value)
		if err != nil {
			return ""
		}
		return base64.RawStdEncoding.EncodeToString(marshal)
	}
}

func ToRawUrlBase64(value any) string {
	if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
		return ""
	}
	switch value.(type) {
	case []byte:
		return base64.RawURLEncoding.EncodeToString(value.([]byte))
	case string:
		return base64.RawURLEncoding.EncodeToString([]byte(value.(string)))
	case error:
		return base64.RawURLEncoding.EncodeToString([]byte(value.(error).Error()))
	default:
		marshal, err := json.Marshal(value)
		if err != nil {
			return ""
		}
		return base64.RawURLEncoding.EncodeToString(marshal)
	}
}

func ToBigInt[T any](v T) (*big.Int, error) {
	result := new(big.Int)

	switch v := any(v).(type) {
	case int:
		result.SetInt64(int64(v)) // Convert to int64 for big.Int
	case int8:
		result.SetInt64(int64(v))
	case int16:
		result.SetInt64(int64(v))
	case int32:
		result.SetInt64(int64(v))
	case int64:
		result.SetInt64(v)
	case uint:
		result.SetUint64(uint64(v)) // Convert to uint64 for big.Int
	case uint8:
		result.SetUint64(uint64(v))
	case uint16:
		result.SetUint64(uint64(v))
	case uint32:
		result.SetUint64(uint64(v))
	case uint64:
		result.SetUint64(v)
	default:
		return nil, fmt.Errorf("unsupported type: %T", v)
	}

	return result, nil
}

// JsonToAny json转对象
// 输入非nil返回对象
func JsonToAny[T any](strJson string) (*T, error) {
	var result T
	err := json.Unmarshal([]byte(strJson), &result)
	if err != nil {
		return nil, err
	}
	return &result, nil
}

// DecimalToHex 十进制转十六进制
//
//	number 十进制数字
//	string 十六进制数字
func DecimalToHex(number int64) string {
	result := strconv.FormatInt(number, 16)
	if len(result) == 1 {
		result = "0" + result
	}
	return result
}

// FormatAlpha 浮点数转透明度
//
//	val 浮点数
//	uint8 透明度
func FormatAlpha(val float32) uint8 {
	a := math.Min(float64(val), 1)
	alpha := a * 255
	return uint8(alpha)
}

// RgbToHex RGB转HEX
// rgb 颜色
// hex 颜色
// 示例：RgbToHex(255, 255, 255)
func RgbToHex(red int64, green int64, blue int64) string {
	r := DecimalToHex(red)
	g := DecimalToHex(green)
	b := DecimalToHex(blue)
	return r + g + b
}

// HexToRgb HEX转RGB
// hex 颜色
// rgb 颜色
// 示例：HexToRgb("ffffff")
func HexToRgb(hexStr string) (r int64, g int64, b int64) {
	r, _ = strconv.ParseInt(hexStr[:2], 16, 10)
	g, _ = strconv.ParseInt(hexStr[2:4], 16, 10)
	b, _ = strconv.ParseInt(hexStr[4:], 16, 10)
	return r, g, b
}

// ParseHexColor 解析HEX颜色
// hex 颜色
// color.RGBA 颜色
// 示例：ParseHexColor("#ffffff")
func ParseHexColor(s string) (c color.RGBA, err error) {
	c.A = 0xff
	if s[0] != '#' {
		return c, errors.New("invalid format")
	}

	hexToByte := func(b byte) byte {
		switch {
		case b >= '0' && b <= '9':
			return b - '0'
		case b >= 'a' && b <= 'f':
			return b - 'a' + 10
		case b >= 'A' && b <= 'F':
			return b - 'A' + 10
		}
		err = errors.New("invalid format")
		return 0
	}
	switch len(s) {
	case 7:
		c.R = hexToByte(s[1])<<4 + hexToByte(s[2])
		c.G = hexToByte(s[3])<<4 + hexToByte(s[4])
		c.B = hexToByte(s[5])<<4 + hexToByte(s[6])
	case 4:
		c.R = hexToByte(s[1]) * 17
		c.G = hexToByte(s[2]) * 17
		c.B = hexToByte(s[3]) * 17
	default:
		err = errors.New("invalid format")
	}
	return
}

// PrettyJson 格式化json输出
func PrettyJson(v any) (jsonStr string, err error) {
	outJson, err := json.MarshalIndent(v, "", "  ")
	return string(outJson), err
}

// MustPrettyJson 格式化输出
func MustPrettyJson(v any) string {
	outJson, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		panic(err)
	}
	return string(outJson)
}
